package com.zbl.zblproject.erp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Preconditions;
import com.zbl.zblproject.core.entity.AdminUser;
import com.zbl.zblproject.core.mapper.BrandMapper;
import com.zbl.zblproject.core.mapper.SupplierMapper;
import com.zbl.zblproject.erp.entity.*;
import com.zbl.zblproject.erp.mapper.*;
import com.zbl.zblproject.erp.service.ErpInventoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * @author youlanqiang
 * @version 1.0
 * @date 2018/10/19
 */
@Service
public class ErpInventoryServiceImpl implements ErpInventoryService {


    @Autowired
    private ErpInventoryOrderMapper inventoryOrderMapper;

    @Autowired
    private ErpInventoryOrderItemMapper inventoryOrderItemMapper;

    @Autowired
    private ErpGoodMapper erpGoodMapper;

    @Autowired
    private ErpWarehouseItemMapper warehouseItemMapper;

    @Autowired
    private ErpLeaveItemMapper leaveItemMapper;


    @Autowired
    private BrandMapper erpBrandMapper;

    @Autowired
    private ErpCategoryMapper erpCategoryMapper;

    @Autowired
    private SupplierMapper erpSupplierMapper;

    @Autowired
    private ErpWarehouseMapper erpWarehouseMapper;

    private static final Logger logger = LoggerFactory.getLogger(ErpInventoryService.class);


    @Override
    public ErpInventoryOrder getOrderBySn(String orderSn) {
        QueryWrapper<ErpInventoryOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("inventory_sn", orderSn);
        ErpInventoryOrder order =  inventoryOrderMapper.selectOne(wrapper);
        return order;
    }

    @Override
    public boolean updateOrderContext(String orderSn, String context) {
        ErpInventoryOrder order = getOrderBySn(orderSn);
        if(order == null){
            return false;
        }
        order.setContext(context);
        return inventoryOrderMapper.updateById(order) == 1;
    }

    @Override
    public boolean rollback(int id) {
        ErpInventoryOrder order = inventoryOrderMapper.selectById(id);
        if(order == null || order.getStatus() != 1){
            throw new RuntimeException("订单不存在,或者订单状态无效");
        }
        order.setStatus(1);
        return inventoryOrderMapper.updateById(order) == 1;
    }

    @Override
    public List<ErpInventoryOrderItem> orderItemByOrderSn(String orderSn) {

        ErpInventoryOrder order = selectByOrderSn(orderSn);
        Preconditions.checkNotNull(order, "订单不存在");
        QueryWrapper<ErpInventoryOrderItem> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", order.getId());
        final int status = order.getStatus();
            List<ErpInventoryOrderItem> items = inventoryOrderItemMapper.selectList(wrapper);
            items.forEach(x->{
                ErpGoods goods = getGoods(x.getGoodsId());
                if(status == 1){
                    x.setRealNum(selectGoodsNumInTheShelf(x.getGoodsId(), x.getWhId()));
                }
                goods.setErpBrand(erpBrandMapper.selectById(goods.getBrandId()));
                goods.setErpCategory(erpCategoryMapper.selectById(goods.getCatId()));
                goods.setErpSupplier(erpSupplierMapper.selectById(goods.getSuppliersId()));
                ErpWarehouse erpWarehouse = erpWarehouseMapper.selectById(x.getWhId());
                x.setWarehouse(erpWarehouse);
                x.setGoods(goods);
                x.setRealPrice(goods.getShopPrice());
                x.setLeaveNum(leaveItemMapper.leaveNum(x.getId()));
            });
            return items;

    }

    @Override
    @Transactional
    public boolean updateOrder(String orderSn) {
        ErpInventoryOrder order = selectByOrderSn(orderSn);
        if(order == null) {
            return false;
        }
        List<ErpInventoryOrderItem> items = orderItemByOrderSn(orderSn);
        if(order.getStatus() == 0){
            //订单由草稿 --> 审核中
            order.setStatus(1);
            items.forEach(x->{
                /**
                 * 现在只返回对应货位上的数量
                 */
                x.setRealNum(selectGoodsNumInTheShelf(x.getGoodsId(), x.getWhId()));
                inventoryOrderItemMapper.updateById(x);
            });
            return inventoryOrderMapper.updateById(order) == 1;
        }
        if(order.getStatus() == 1){
            //订单由审核中 --> 审核成功
            order.setStatus(2);
            order.setIsRecom(1);
            items.forEach(x->{
                //改变货架上仓库的值,并且改变goods的库存值

                updateTheShelfNum(order.getMode(), x);

            });
            return inventoryOrderMapper.updateById(order) == 1;
        }
        return false;
    }

    @Override
    public IPage<ErpInventoryOrder> page(String search, int current, int size) {
        Page<ErpInventoryOrder> page = new Page<>(current, size);
        QueryWrapper<ErpInventoryOrder> wrapper = new QueryWrapper<>();
        wrapper.apply(search).orderByDesc("id");
        return inventoryOrderMapper.selectPage(page, wrapper);
    }


    @Override
    @Transactional
    public ErpInventoryOrder createOrderByStatus(int mode, String orderSn,  String context, final int status, AdminUser user, List<ErpInventoryOrderItem> orderItems) {
        ErpInventoryOrder order = selectByOrderSn(orderSn);
        boolean needUp = false;
        if(orderItems.isEmpty()){
            throw new RuntimeException("订单项目不能为空");
        }
        if(status != 0 && status != 1){
            throw new RuntimeException("订单状态异常");
        }
        if(order == null){
            //新建订单
            order = new ErpInventoryOrder();
            needUp = true;
        }
        order.setContext(context);
        order.setMode(mode);
        order.setOperator(user.getUserName());
        order.setStatus(status);
        order.setCreateTime(LocalDateTime.now());
        order.setInventorySn(orderSn);
        order.setIsRecom(0);
        if(needUp){
            inventoryOrderMapper.insert(order);
        }else{
            inventoryOrderMapper.updateById(order);
        }
        final int orderId = order.getId();
        reviewOrder(order, orderItems, (x)->{
            if(status == 1){
                x.setRealNum(selectGoodsNumInTheShelf(x.getGoodsId(), x.getWhId()));
            }
            x.setOrderId(orderId);
            inventoryOrderItemMapper.insert(x);
        });
        return order;
    }


    @Override
    public boolean deleteOrderById(int id) {
        ErpInventoryOrder order = inventoryOrderMapper.selectById(id);
        if(order == null){
            return false;
        }
        if(order.getStatus() != 0 && order.getStatus() != 1){
            return false;
        }
        QueryWrapper<ErpInventoryOrderItem> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", id);
        inventoryOrderItemMapper.delete(wrapper);
        return 1 == inventoryOrderMapper.deleteById(id);
    }

    @Override
    @Transactional
    public boolean flushOrder(String orderSn, List<ErpInventoryOrderItem> orderItems){
        ErpInventoryOrder order = selectByOrderSn(orderSn);
        if(order == null){
            throw new RuntimeException("没有发现对应订单!");
        }
        if(order.getStatus() != 2 && order.getStatus() != 1){
            throw new RuntimeException("订单状态只能是,待审核和审核通过");
        }
        if(order.getMode() != 0){
            throw new RuntimeException("只能对盘库单进行提交遗漏!");
        }
        orderItems.forEach(x->{
            ErpInventoryOrderItem orderItem = getOrderItemByOrderIdAndGoodsId(order.getId(), x.getGoodsId(), x.getWhId());
            if(orderItem == null){
                throw new RuntimeException("没有这个盘点项");
//                orderItem = x;
//                orderItem.setOrderId(order.getId());
//                inventoryOrderItemMapper.insert(orderItem);
            }else{

                orderItem.setInventoryNum(orderItem.getInventoryNum() + x.getInventoryNum());
                leaveItemMapper.insert(new ErpLeaveItem(orderItem.getId(), x.getInventoryNum()));
                inventoryOrderItemMapper.updateById(orderItem);
            }
            if(order.getStatus() == 2) {
                updateTheShelfNum(order.getMode(), orderItem);
            }
        });
        return inventoryOrderMapper.updateById(order) == 1;
    }

    private ErpInventoryOrderItem getOrderItemByOrderIdAndGoodsId(int orderId, int goodsId, int whId){
        QueryWrapper<ErpInventoryOrderItem> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", orderId).eq("goods_id", goodsId).eq("wh_id", whId);
        return inventoryOrderItemMapper.selectOne(wrapper);
    }


    private void updateTheShelfNum(int mode, ErpInventoryOrderItem x){
        QueryWrapper<ErpWarehouseItem> wrapper = new QueryWrapper<>();
        wrapper.eq("goods_id", x.getGoodsId()).eq("wh_id", x.getWhId());
        ErpWarehouseItem item = warehouseItemMapper.selectOne(wrapper);
        ErpGoods goods = erpGoodMapper.selectById(x.getGoodsId());

        Preconditions.checkNotNull(goods, "没有发现对应商品ID{"+x.getGoodsId()+"}");

        switch(mode){
            case 0: //盘货单
                if(item == null){
                    item = new ErpWarehouseItem();
                    item.setStock(x.getInventoryNum());
                    item.setWhId(x.getWhId());
                    item.setGoodsId(x.getGoodsId());
                    warehouseItemMapper.insert(item);
                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }else{
                    item.setStock(x.getInventoryNum());
                    warehouseItemMapper.updateById(item);
                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }
                goods.setShopPrice(x.getInventoryPrice());
                break;
            case 1: //报损单
                if(item == null){

                   throw new RuntimeException("没有发现货架上的商品{"+goods.getGoodsName()+"}!");
                }else{
                    int realStock =  item.getStock();
                    if(goods.getGoodsNumber() < 0){
                        throw new RuntimeException("领取超出商品{"+goods.getGoodsName()+"}数量的数量!");
                    }
                    item.setStock(realStock - x.getInventoryNum());
                    if(item.getStock() < 0){
                        throw new RuntimeException("领取超出货架{"+item.getWhId()+"}上的商品{"+goods.getGoodsName()+"}数量，" +
                                "货架上只有数量{"+item.getStock()+"}！");
                    }
                    warehouseItemMapper.updateById(item);
                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }
                break;
            case 2: //领用单
                if(item == null){
                    throw new RuntimeException("没有发现货架上的商品{"+goods.getGoodsName()+"}!");
                }else{
                    int realStock =  item.getStock();
                    if(goods.getGoodsNumber() < 0){
                        throw new RuntimeException("领取超出商品{"+goods.getGoodsName()+"}数量的数量!");
                    }
                    item.setStock(realStock - x.getInventoryNum());
                    if(item.getStock() < 0){
                        throw new RuntimeException("领取超出货架{"+item.getWhId()+"}上的商品{"+goods.getGoodsName()+"}数量，" +
                                "货架上只有数量{"+item.getStock()+"}！");
                    }
                    warehouseItemMapper.updateById(item);
                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }
                break;
            case 3: //退货单
                if(item == null){
//                    item = new ErpWarehouseItem();
//                    item.setStock(x.getInventoryNum());
//                    item.setWhId(x.getWhId());
//                    item.setGoodsId(x.getGoodsId());
//                    warehouseItemMapper.insert(item);
//                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }else{
                    int realStock =  item.getStock();
                    item.setStock(realStock - x.getInventoryNum());
                    warehouseItemMapper.updateById(item);
                    goods.setGoodsNumber(warehouseItemMapper.getGoodsNumber(goods.getGoodsId()));
                }
                break;
            default:
                throw new RuntimeException("没有发现对应订单模式");
        }
        logger.info("更新后的库存数量:{}", goods.getGoodsNumber());
        erpGoodMapper.updateById(goods);
    }


    /**
     * 订单项目重置
     * @param order
     * @param items
     */
    private void reviewOrder(final ErpInventoryOrder order, List<ErpInventoryOrderItem> items, Consumer<ErpInventoryOrderItem> consumer){
        //删除该订单下的所有原始数据
        QueryWrapper<ErpInventoryOrderItem> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", order.getId());
        inventoryOrderItemMapper.delete(wrapper);
        items.forEach(consumer);
    }

    private ErpInventoryOrder selectByOrderSn(String orderSn){
        QueryWrapper<ErpInventoryOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("inventory_sn", orderSn);
        return inventoryOrderMapper.selectOne(wrapper);
    }


    /**
     * 查询当前仓库上商品的数量
     * @param goodsId 商品ID
     * @param whId   仓库ID
     * @return
     */
    private int selectGoodsNumInTheShelf(int goodsId, int whId){
        QueryWrapper<ErpWarehouseItem> wrapper = new QueryWrapper<>();
        wrapper.eq("goods_id", goodsId).eq("wh_id", whId);
        ErpWarehouseItem item = warehouseItemMapper.selectOne(wrapper);
        if(item == null){
            return 0;
        }
        return item.getStock();
    }

    /**
     * 获取Goods的库存数量
     * @param goodsId
     * @return
     */
    private ErpGoods getGoods(int goodsId){
        QueryWrapper<ErpGoods> wrapper = new QueryWrapper<>();
        wrapper.eq("goods_id", goodsId);
        ErpGoods goods = erpGoodMapper.selectOne(wrapper);
        return goods;
    }
}
